{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "91af3eba",
   "metadata": {},
   "outputs": [],
   "source": [
    "%use fuel(2.3.1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "d86fa867",
   "metadata": {},
   "outputs": [],
   "source": [
    "val envs = java.io.File(\"../../.env\")\n",
    "    .readLines()\n",
    "    .map {\n",
    "        it.split(\"=\")[0] to it.split(\"=\")[1].trim('\"')\n",
    "    }.toMap()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "65e62477",
   "metadata": {},
   "outputs": [],
   "source": [
    "val session = envs.get(\"AOC_SESSION\")\n",
    "val year = 2021\n",
    "val day = 16"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "a2bb91d0",
   "metadata": {},
   "outputs": [],
   "source": [
    "fun getInput(year: Int, day: Int, session: String): String {\n",
    "    val (_, _, result) = \"https://adventofcode.com/$year/day/$day/input\"\n",
    "    .httpGet()\n",
    "    .header(\"cookie\" to \"session=$session\")\n",
    "    .responseString()\n",
    "        \n",
    "    return result.get().trim()\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "f0917bbf",
   "metadata": {},
   "outputs": [],
   "source": [
    "fun submitAnswer(year: Int, day: Int, session: String, level: Int, answer: String): String {\n",
    "    val (_, _, result) = Fuel\n",
    "    .post(\n",
    "        \"https://adventofcode.com/$year/day/$day/answer\", \n",
    "        parameters = listOf(\"level\" to level, \"answer\" to answer))\n",
    "    .header(\"cookie\" to \"session=$session\")\n",
    "    .responseString()\n",
    "        \n",
    "    return result.get()\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "dd0e5a59",
   "metadata": {},
   "outputs": [],
   "source": [
    "val sample = \"\"\"D2FE28\"\"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "83fc6186",
   "metadata": {},
   "outputs": [],
   "source": [
    "val input = getInput(year, day, session)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "986b4544",
   "metadata": {},
   "outputs": [],
   "source": [
    "enum class ExpressionType(val value: Int) {\n",
    "    SUM(0),\n",
    "    PROD(1),\n",
    "    MIN(2),\n",
    "    MAX(3),\n",
    "    LIT(4),\n",
    "    GT(5),\n",
    "    LT(6),\n",
    "    EQ(7),\n",
    "    NULL(8);\n",
    "\n",
    "    companion object {\n",
    "        fun fromInt(value: Int) = ExpressionType.values().first { it.value == value }\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "3c5f0251",
   "metadata": {},
   "outputs": [],
   "source": [
    "class Expression {\n",
    "    val children = mutableListOf<Expression>()\n",
    "    var value = 0L\n",
    "    var version = 0\n",
    "    var versionSum = 0\n",
    "    var offset = 0\n",
    "    var length = 0\n",
    "    var type = ExpressionType.NULL\n",
    "    \n",
    "    constructor(bits: String, offset: Int) {\n",
    "        this.offset = offset\n",
    "        var ptr = offset\n",
    "        version = bits.slice(ptr until ptr + 3).toInt(radix = 2)\n",
    "        versionSum = version\n",
    "        type = ExpressionType.fromInt(bits.slice(ptr + 3 until ptr + 6).toInt(radix = 2))\n",
    "        \n",
    "        ptr += 6\n",
    "        if (type == ExpressionType.LIT) {\n",
    "            while (bits[ptr] != '0') {\n",
    "                value = value.shl(4)\n",
    "                value += bits.slice(ptr + 1 until ptr + 5).toInt(radix = 2)\n",
    "                ptr += 5\n",
    "            }\n",
    "            value = value.shl(4)\n",
    "            value += bits.slice(ptr + 1 until ptr + 5).toInt(radix = 2)\n",
    "            ptr += 5\n",
    "        } else {\n",
    "            if (bits[ptr] == '0') {\n",
    "                val subLength = bits.slice(ptr + 1 until ptr + 16).toInt(radix = 2)\n",
    "                ptr += 16\n",
    "                while (ptr < offset + 22 + subLength) {\n",
    "                    val child = Expression(bits, ptr)\n",
    "                    children.add(child)\n",
    "                    ptr += child.length\n",
    "                    versionSum += child.versionSum\n",
    "                }\n",
    "            } else {\n",
    "                val subCount = bits.slice(ptr + 1 until ptr + 12).toInt(radix = 2)\n",
    "                ptr += 12\n",
    "                repeat(subCount) {\n",
    "                    val child = Expression(bits, ptr)\n",
    "                    children.add(child)\n",
    "                    ptr += child.length\n",
    "                    versionSum += child.versionSum\n",
    "                }\n",
    "            }\n",
    "            \n",
    "            assert(children.size >= 1)\n",
    "            when (type) {\n",
    "                ExpressionType.SUM -> { value = children.map { it.value }.sum() }\n",
    "                ExpressionType.PROD -> { value = children.fold(1L, {acc, it -> acc * it.value}) }\n",
    "                ExpressionType.MIN -> { value = children.map { it.value }.minOrNull()!! }\n",
    "                ExpressionType.MAX -> { value = children.map { it.value }.maxOrNull()!! }\n",
    "                ExpressionType.GT -> { value = if (children[0].value > children[1].value) 1 else 0 }\n",
    "                ExpressionType.LT -> { value = if (children[0].value < children[1].value) 1 else 0 }\n",
    "                ExpressionType.EQ -> { value = if (children[0].value == children[1].value) 1 else 0 }\n",
    "                else -> {}\n",
    "            }\n",
    "        }\n",
    "        \n",
    "        length = ptr - offset\n",
    "    }\n",
    "    \n",
    "    override fun toString(): String {\n",
    "        return when (type) {\n",
    "            ExpressionType.NULL -> \"\"\n",
    "            ExpressionType.LIT -> value.toString()\n",
    "            else -> {\n",
    "                val parts = mutableListOf<String>()\n",
    "                parts.add(\"(\")\n",
    "                val op = when (type) {\n",
    "                    ExpressionType.SUM -> \"+\"\n",
    "                    ExpressionType.PROD -> \"*\"\n",
    "                    ExpressionType.MIN -> \"min\"\n",
    "                    ExpressionType.MAX -> \"max\"\n",
    "                    ExpressionType.GT -> \">\"\n",
    "                    ExpressionType.LT -> \"<\"\n",
    "                    ExpressionType.EQ -> \"=\"\n",
    "                    else -> \"\" // should not enter here\n",
    "                }\n",
    "                parts.add(op)\n",
    "                parts.addAll(children.map { it.toString() })\n",
    "                parts.add(\")\")\n",
    "                parts.joinToString(\" \")\n",
    "            }\n",
    "        }\n",
    "    }\n",
    "    \n",
    "    companion object {\n",
    "        fun fromHex(hex: String) = Expression(\n",
    "            hex.map { it.toString().toInt(radix = 16).toString(radix = 2).padStart(4, '0') }.joinToString(\"\"),\n",
    "            0\n",
    "        )\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "a7aaf9b7",
   "metadata": {},
   "outputs": [],
   "source": [
    "val samples = listOf(\n",
    "    sample,\n",
    "    \"38006F45291200\",\n",
    "    \"EE00D40C823060\",\n",
    "    \"8A004A801A8002F478\",\n",
    "    \"620080001611562C8802118E34\",\n",
    "    \"C0015000016115A2E0802F182340\",\n",
    "    \"A0016C880162017C3686B18A3D4780\",\n",
    "    \"C200B40A82\",\n",
    "    \"04005AC33890\",\n",
    "    \"880086C3E88112\",\n",
    "    \"CE00C43D881120\",\n",
    "    \"D8005AC2A8F0\",\n",
    "    \"F600BC2D8F\",\n",
    "    \"9C005AC2F8F0\",\n",
    "    \"9C0141080250320F1802104A08\",\n",
    "    input,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "d9c099e0",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2021\n",
      "( < 10 20 )\n",
      "( max 1 2 3 )\n",
      "( min ( min ( min 15 ) ) )\n",
      "( + ( + 10 11 ) ( + 12 13 ) )\n",
      "( + ( + 10 11 ) ( + 12 13 ) )\n",
      "( + ( + ( + 6 6 12 15 15 ) ) )\n",
      "( + 1 2 )\n",
      "( * 6 9 )\n",
      "( min 7 8 9 )\n",
      "( max 7 8 9 )\n",
      "( < 5 15 )\n",
      "( > 5 15 )\n",
      "( = 5 15 )\n",
      "( = ( + 1 3 ) ( * 2 2 ) )\n",
      "( + ( * 445572 ( = ( + 8 8 11 ) ( + 2 12 7 ) ) ) ( * 238471898 ( < 5 125441674 ) ) ( * 17226 ( > 265949656 90 ) ) ( min 92 138 189 ) ( max 333045 1 635818 3837 ) ( * ( > 32733 32733 ) 10192146 ) ( min ( * ( min ( min ( max ( + ( + ( min ( max ( * ( * ( max ( max ( max ( + ( * ( min ( * ( * ( max 2478414062 ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ( * 215 ) 12 ( * 863908 ( > ( + 13 12 3 ) ( + 6 13 12 ) ) ) ( + 752712 4152413765 ) ( * 195 ( < ( + 12 3 14 ) ( + 10 13 13 ) ) ) ( * 130 ( < 2188 2188 ) ) ( * ( > 528325 1666 ) 3205 ) 146272 ( + ( * 3 7 8 ) ( * 11 3 6 ) ( * 6 5 2 ) ) ( * 220 50 62 54 135 ) ( * ( > ( + 10 10 8 ) ( + 13 11 14 ) ) 147 ) ( * ( = 45179 45179 ) 17086 ) ( * 5802 ( < 595085 595085 ) ) 3007 ( * 4419 ( < 8 16198656 ) ) 15234625 2358 64817 ( + 3 4650320 36420 ) ( * 39 19 ) ( + 14 ) ( max 31807 ) 328237 222 ( min 70 11 20243 763 ) ( * 2314 ( = 985 3972 ) ) ( max 39856 13544890 6 ) ( max 5648 3759402689 24148481501 33 59290 ) ( min 7 10 ) ( * ( < 14201 36 ) 149756 ) ( * 118 252 32 64 ) ( + 2760473 32415360231 19 14361 43105 ) ( max 590323 1103 ) ( * ( + 5 12 13 ) ( + 4 11 14 ) ( + 7 12 14 ) ) ( * 13 ( < ( + 14 3 4 ) ( + 12 5 4 ) ) ) 52738972 ( * ( > 2732 602671 ) 35513 ) ( min 53117 ) ( + 498 144929501 2 1908 ) ( * ( > 579175 579175 ) 15051 ) ( * 201 27 102 ) ( * 101912 ( = 173 104 ) ) 4 ( min 4175916500 16063226 11119083 15 1753 ) ( * 123647130 ( > 39124 496010 ) ) ( * ( < 6302962 855422 ) 49099018863 ) )\n"
     ]
    }
   ],
   "source": [
    "samples.forEach { \n",
    "    println(Expression.fromHex(it))\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "c542c6ac",
   "metadata": {},
   "outputs": [],
   "source": [
    "fun partOne(input: String): String {\n",
    "    return Expression.fromHex(input).versionSum.toString()\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "cc01ce3c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "6"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "partOne(sample)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "a94d0dcb",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "871"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "val partOneAns = partOne(input)\n",
    "partOneAns"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6e0d4935",
   "metadata": {},
   "outputs": [],
   "source": [
    "submitAnswer(year, day, session, 1, partOneAns)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "9e7a88eb",
   "metadata": {},
   "outputs": [],
   "source": [
    "fun partTwo(input: String): String {\n",
    "    return Expression.fromHex(input).value.toString()\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "261894c7",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2021"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "partTwo(sample)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "11f62ebc",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "68703010504"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "val partTwoAns = partTwo(input)\n",
    "partTwoAns"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "899192ae",
   "metadata": {},
   "outputs": [],
   "source": [
    "submitAnswer(year, day, session, 2, partTwoAns)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Kotlin",
   "language": "kotlin",
   "name": "kotlin"
  },
  "language_info": {
   "codemirror_mode": "text/x-kotlin",
   "file_extension": ".kt",
   "mimetype": "text/x-kotlin",
   "name": "kotlin",
   "nbconvert_exporter": "",
   "pygments_lexer": "kotlin",
   "version": "1.6.20-dev-6372"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
